Skip to main content

Optional

Atem provides null safety by providing language built-in optional types.

The question mark symbolizes the optional type, you can convert types to optional types by putting a question mark in front of them, like:

optional_int mutable: ?i8 = 12;
optional_int = null;

Now the variable optional_int could be an i8 or null.

Optional Types

You can create optional type by putting a ? in front of the type:

opt_int mutable: ?i8 = 12;

To access the child type of an optional type, use compile-time reflection:

assert(^opt_int.getType().getChildType() == i8);

You can initialize or assign null to an optional to mean the optional is "empty":

opt_int = null;

To use the value of the optional, you need to unwrap it:

int1 := opt_int ?? -1;  //the int1 would be -1 when the opt_int is null
int2 := try opt_int.?; //will throw an UnwrappingException when the opt_int is null
int3 := opt_int.!; //will terminate program at runtime or terminate compilation at compile-time

If the child type of an optional has members, the optional chaining operator !. and ?. will be used to access them:

blog : struct = {
id: u8;
name: string;
checkBlogValidity: () -> bool func {...};
};

blog_opt: ?blog = .{id = 3, name = "std-atem"};
id := try blog_opt?.id;
//equivalent to:
id := try blog_opt.?.id;

name := blog_opt!.name; //will terminate program at runtime or terminate compilation at compile-time
//equivalent to:
name := blog_opt.!.name;

Optional Pointers

The normal pointers in Atem couldn't be null. If you want a pointer to be nullable, use optional pointer instead:

ptr mutable: i8.& = null;   //compile error
opt_ptr mutable: ?i8.& = null; //good

The optional pointer is guaranteed to be the same size of the child pointer type:

assert(^opt_ptr.getType().size() == ^i8.&.size());